package wortubung.core;

import java.util.Random;

import static wortubung.util.CommonUtils.*;

public class TestLine implements Comparable<TestLine> {
    static final String MARKER_TF = "::>";
    static final String MARKER_TR = "<::";
    static final String MARKER_D1 = "{";
    static final String MARKER_D2 = "}";
    static final String CONJUGATE_MARKER = "_conj_";

    static Random  random = new Random();
    public static boolean isConjugate = false;

    private String  line;
    private boolean ignore;
    private boolean isValid;
    private String  wordText;
    private POS     pos;
    private String  plural;
    private String  conjugation;
    private String  answerText;
    private String  errorMessage;

    private String  digest;
    private boolean isReverse;
    // if isReverse == true, only 'word' matter.

    private WORD wordInfo;

    public boolean ignore()  { return ignore; }
    public boolean isValid() { return isValid; }
    public boolean isReverse() { return isReverse; }
    public boolean isWrong() { return isNotEmpty(errorMessage); }
    public String  getAnswerWord() { return wordText; }
    public String  getAnswerText() { return answerText; }
    public String  getDigest() { return digest; }
    public String  getPlural() { return plural; }
    public String  getConjugation() { return conjugation; }
    public String  getLine() { return line; }
    public POS     getPOS() { return pos; }
    public WORD    getWORD() { return wordInfo; }
    public String  getErrorMessage() { return errorMessage; }

    public void setIsValid(boolean isValid, String errorMsg) {
        this.isValid = isValid;
        this.errorMessage = isValid ? null : errorMsg;
    }

    public TestLine(String answerLine) {
        int idx1;
        this.line = answerLine = answerLine.trim();
        setIsValid(false, "INVALID");

        int idx = answerLine.indexOf(MARKER_D2);
        if (answerLine.indexOf(MARKER_TF) < 0 && answerLine.indexOf(MARKER_TR) < 0 || !answerLine.startsWith(MARKER_D1) || idx < 0) {
            ignore = true;
            return;
        }

        ignore = false;
        digest = answerLine.substring(MARKER_D1.length(), idx).trim();

        idx = answerLine.indexOf(MARKER_TR);
        isReverse = (idx > 0);
        if (isReverse) {
            // Reverse Test:
            answerLine = answerLine.substring(idx + MARKER_TR.length());
            isReverse = true;
            wordText = answerLine.trim();
            setIsValid(true, null);
            return;
        }

        // Non-Reverse Test:
        idx = answerLine.indexOf(MARKER_TF);
        answerLine = answerLine.substring(idx + MARKER_TF.length());

        idx = answerLine.indexOf("]");
        if (idx > 0) {
        	idx1 = answerLine.indexOf("[");
        	if (idx1 >= 0) {
        		String[] sa = answerLine.substring(idx1+1, idx).split("/");
        		trim(sa);
        		if (sa.length > 0) {
        			try {
        				pos = POS.fromShortName(sa[0]);
        			} catch(Exception e) {}
        		}
        		if (sa.length > 1)
        			plural = sa[1];
        	}
        	answerLine = answerLine.substring(idx+1).trim();
        }
        idx = answerLine.indexOf("}");
        if (idx > 0) {
        	idx1 = answerLine.indexOf("{");
        	if (idx1 >= 0) {
        		conjugation = answerLine.substring(idx1+1, idx).trim();
        		if (CONJUGATE_MARKER.equals(conjugation))
        			conjugation = null;
           	}
        	answerLine = answerLine.substring(idx+1).trim();
        }

        answerText = answerLine;
        setIsValid(true, null);
    }

    public boolean check(WORD word, boolean strict, LANG lang) {
        this.wordInfo = word;

        if (isReverse) {
            if (isEmpty(this.wordText))
                return fail("No answer.");

            String answer = strict ? word.getWord() : word.getAnglicizedWord();
            for (String result : separate(this.wordText, ",")) {
                if (strict)
                    result = lang.toLatin(result, false);
                if (answer.equals(result))
                    return true;
            }
            return fail("Wrong.");
        }

        return word.checkAnswer(this);
    }

    public boolean fail(String... msgs) {
        if (msgs.length == 1) {
            this.errorMessage = msgs[0];
        } else {
            StringBuilder sb = new StringBuilder();
            for (String msg : msgs) {
                if (sb.length() > 0)
                    sb.append(' ');
                if (isNotEmpty(msg))
                    sb.append(msg);
            }
            this.errorMessage = sb.toString();
        }
        return false;
    }

    public static String toTestLine(WORD word, boolean isReverse, int width) {
        if (isReverse) { // this is simpler
            java.util.List<MEANING> defs = word.getDefinition();
            if (isEmpty(defs))
                return null;
            String meaning = defs.get(random.nextInt(defs.size())).getMeaning();
            meaning = makeStringLen(meaning, 2, width, '.');
            String posDisplay = "/" + word.getDefaultPOS().getShortName() + "/";
            return String.format("%s%-8s%s %-6s%s %s ", MARKER_D1, word.getDigest(), MARKER_D2, posDisplay, meaning, MARKER_TR);
        }

        LANG lang = word.getLang();
        String wordOptions = "";
        if (lang.hasNounGender() || lang.isIrregularPlural()) {
        	wordOptions = "[ ";
//			if (lang.hasNounGender())
//				wordOptions += lang.hasGenderNeuter() ? "mfn" : "mf";
        	if (lang.isIrregularPlural())
        		wordOptions += "/   ";
        	wordOptions += "]";
        }
        if (isConjugate && lang.isConjugated())
        	wordOptions += " {" + CONJUGATE_MARKER + "}";
        String wd = makeStringLen(word.getWordWithAlias(true), 2, width, '.');
        String listName = word.getWordListInfo().getShortName();
        return String.format("%s%-8s%s<%s>  %s %s %s", MARKER_D1, word.getDigest(), MARKER_D2, listName, wd, MARKER_TF, wordOptions);
    }

    public String toResultDisplay(int width) {
    	StringBuilder sb = new StringBuilder(String.format("%-" + width + "s", line));
    	appendWithPrefix(sb, "  -XXX- ", errorMessage);
    	return sb.toString();
    }

    public int compareTo(TestLine toTestLine) {
    	int ret = compare(isValid, toTestLine.isValid);
    	if (ret != 0)
    		return ret;
    	ret = errorMessage.compareTo(toTestLine.errorMessage);
    	if (ret != 0)
    		return ret;
//    	if (criteria != null && criteria.groupByList()) {
//    		ret = wordInfo.getWordListInfo().getShortName().compareTo(toTestLine.wordInfo.getWordListInfo().getShortName());
//    		if (ret != 0)
//    			return ret;
//    	}
    	return wordInfo.getWordWithAlias().compareTo(toTestLine.wordInfo.getWordWithAlias());
    }
}
